package com.micaelvesterlund.skeerkie.server.engine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import com.micaelvesterlund.skeerkie.shared.domain.FinalScore;
import com.micaelvesterlund.skeerkie.shared.domain.Game;
import com.micaelvesterlund.skeerkie.shared.domain.Goalie;
import com.micaelvesterlund.skeerkie.shared.domain.League;
import com.micaelvesterlund.skeerkie.shared.domain.Line;
import com.micaelvesterlund.skeerkie.shared.domain.LineUp;
import com.micaelvesterlund.skeerkie.shared.domain.Player;
import com.micaelvesterlund.skeerkie.shared.domain.Round;
import com.micaelvesterlund.skeerkie.shared.domain.Score;
import com.micaelvesterlund.skeerkie.shared.domain.Standing;
import com.micaelvesterlund.skeerkie.shared.domain.Standings;
import com.micaelvesterlund.skeerkie.shared.domain.Statistics;
import com.micaelvesterlund.skeerkie.shared.domain.Team;
import com.micaelvesterlund.skeerkie.shared.domain.Time;

public class GameEngine {

	private Random random;

	public GameEngine(Random random) {
		this.random = random;
	}

	public FinalScore playGame(Game game) {
		game.start();
		for (int i = 0; i < 60; i++) {
			Time time = new Time(i, 30);
			int pos = i % 3;
			LineUp homeLineUp = game.getHomeLineUp();
			Line[] homeLines = homeLineUp.getLines();
			Line homeLine = homeLines[pos];
			LineUp awayLineUp = game.getAwayLineUp();
			Line[] awayLines = awayLineUp.getLines();
			Line awayLine = awayLines[pos];
			int homeOff = homeLine.getOff() + random();
			int awayOff = awayLine.getOff() + random();
			int homeDef = homeLine.getDef() + random();
			int awayDef = awayLine.getDef() + random();
			if (homeOff > awayOff) {
				if (homeOff > awayDef) {
					// shot
					Player shooter = getShooter(homeLine);
					Goalie goalie = awayLineUp.getGoalie();
					Team team = homeLineUp.getTeam();
					shoot(game, time, shooter, goalie, team);
				}
			} else if (awayOff > homeOff) {
				if (awayOff > homeDef) {
					// shot
					Player shooter = getShooter(awayLine);
					Goalie goalie = homeLineUp.getGoalie();
					Team team = awayLineUp.getTeam();
					shoot(game, time, shooter, goalie, team);
				}
			}
		}
		game.end();
		return game.getFinalScore();
	}

	private void shoot(Game game, Time time, Player shooter, Goalie goalie,
			Team team) {
		shooter.getStatistics().incShots();
		if (shooter.getOff() + random() > goalie.getDef() + random()) {
			// goal!
			shooter.getStatistics().incGoals();
			Score score = new Score(team, time, shooter);
			game.addScore(score);
		}
	}

	private Player getShooter(Line line) {
		int probability = random.nextInt(100);
		if (probability < 10) {
			return line.getLd(); // 10%
		} else if (probability < 20) {
			return line.getRd(); // 10%
		} else if (probability < 45) {
			return line.getLw(); // 25%
		} else if (probability < 70) {
			return line.getRw(); // 25%
		} else {
			return line.getCe(); // 30
		}
	}

	private int random() {
		return random.nextInt(3);
	}

	public void playLeague(League league) {
		playGames(league);
	}

	public Standings calcStandings(League league) {
		List<Standing> standings = new ArrayList<Standing>();
		List<Team> teams = league.getTeams();
		List<Game> games = league.getGames();
		for (Team team : teams) {
			Standing standing = new Standing(team);
			for (Game game : games) {
				if (team.equals(game.getHomeLineUp().getTeam())) {
					if (game.getFinalScore().getHome() > game.getFinalScore()
							.getAway()) {
						standing.incWon();
					} else if (game.getFinalScore().getHome() < game
							.getFinalScore().getAway()) {
						standing.incLost();
					} else {
						standing.incTied();
					}
				} else if (team.equals(game.getAwayLineUp().getTeam())) {
					if (game.getFinalScore().getHome() < game.getFinalScore()
							.getAway()) {
						standing.incWon();
					} else if (game.getFinalScore().getHome() > game
							.getFinalScore().getAway()) {
						standing.incLost();
					} else {
						standing.incTied();
					}
				}
			}
			standings.add(standing);
		}
		Comparator<? super Standing> comparator = new TotalPointsSorter();
		Collections.sort(standings, comparator);
		return new Standings(standings);
	}

	private void playGames(League league) {
		List<Round> rounds = league.getRounds();
		for (Round round : rounds) {
			Game[] games = round.getGames();
			for (Game game : games) {
				playGame(game);
			}
		}
	}
}
